package org.java.assembler;

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

/**
 *
 */
public class Assembler {

    public static void main(String[] args) throws IOException, URISyntaxException {
        File asmFile = Paths.get(Assembler.class.getResource("/" + args[0]).toURI()).toFile();
        BinGenerator binGenerator = new BinGenerator(asmFile);
        binGenerator.write(assemble(asmFile));
        binGenerator.close();
    }

    public static String assemble(File asmFile) throws IOException {
        StringBuilder sb = new StringBuilder();
        SymbolTable symbolTable = new SymbolTable();
        phaseOne(asmFile, symbolTable);
        List<Bits> bitList = phaseTwo(asmFile, symbolTable);
        bitList.forEach(bits -> sb.append(bits.getEssence()).append("\r\n"));
        return sb.toString();
    }

    /**
     * 第一阶段，标号处理
     */
    private static void phaseOne(File asmFile, SymbolTable symbolTable) throws IOException {
        int romAddress = 0;
        Parser parser = new Parser(asmFile);
        while (parser.hasMoreCommand()) {
            parser.advance();
            CommandType commandType = parser.commandType();
            if (commandType == CommandType.L_COMMAND) {
                symbolTable.addEntry(parser.symbol(), romAddress);
            } else {
                romAddress++;
            }
        }
    }

    private static List<Bits> phaseTwo(File asmFile, SymbolTable symbolTable) throws IOException {
        List<Bits> list = new ArrayList<>();
        Parser parser = new Parser(asmFile);
        Code code = new Code();
        Variable variable = new Variable();

        while (parser.hasMoreCommand()) {
            parser.advance();
            CommandType commandType = parser.commandType();
            if (commandType == CommandType.A_COMMAND) {
                String symbol = parser.symbol();
                Bits aBits = createABits(symbolTable, symbol, variable);

                list.add(Bits.defaultAPrefix().append(aBits));
            } else if (commandType == CommandType.C_COMMAND) {
                Bits dest = code.dest(parser.dest());
                Bits comp = code.comp(parser.comp());
                Bits jump = code.jump(parser.jump());

                list.add(Bits.defaultCPrefix()
                        .append(Bits.defaultCReserved())
                        .append(comp).append(dest)
                        .append(jump));
            }
        }
        return list;
    }

    private static Bits createABits(SymbolTable symbolTable, String symbol, Variable variable) {
        int address = -1;
        if (symbolTable.contains(symbol)) {
            address = symbolTable.getAddress(symbol);
        } else {
            try {
                address = Integer.parseInt(symbol);
            } catch (Exception e) {
                // 变量处理
                address = variable.getAddress();
                symbolTable.addEntry(symbol, address);
            }
        }
        String binaryString = Integer.toBinaryString(address);
        return Bits.createBits(String.format("%015d", Long.parseLong(binaryString)));
    }
}
